
/*
 * 文件名：ShardingTableHelper.java
 * 版权：Copyright by kalvan
 * 修改人：chenliang
 * 修改时间：2018年11月26日
 * 修改内容：
 */

package com.kalvan.core.mybatis.util;

import com.kalvan.core.exception.BizException;
import com.kalvan.core.mybatis.annotation.ShardingUk;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.UnknownTypeHandler;
import tk.mybatis.mapper.annotation.ColumnType;
import tk.mybatis.mapper.entity.EntityColumn;
import tk.mybatis.mapper.entity.EntityField;
import tk.mybatis.mapper.mapperhelper.FieldHelper;
import tk.mybatis.mapper.util.StringUtil;

import javax.persistence.Column;
import javax.persistence.Transient;
import java.util.*;

/**
 * Sharding UK 工具类
 *
 * @author chenliang
 */
@Slf4j
public class ShardingTableHelper {
    /**
     * 所有的UK
     */
    private static Map<String, List<EntityColumn>> shardingUKColumnMap = new HashMap<>();

    public static String whereShardingUKColumns(Class<?> entityClass) {
        List<EntityColumn> columnSet = getShardingUKColumns(entityClass);
        if (columnSet.isEmpty()) {
            // 使用UK方法为了避免分表带来的问题,必须要指定业务唯一键不能用主键
            log.error("{}本次查询条件使用Id,请使用@ShardingUk标记表中唯一字段后使用该API避免分表下id重复", entityClass.getName());
            throw new BizException("请使用@ShardingUk标记表中唯一字段后使用该API");
//            return SqlHelper.wherePKColumns(entityClass);
        }
        Iterator iterator = columnSet.iterator();
        StringBuilder sql = new StringBuilder();
        sql.append("<where>");

        while (iterator.hasNext()) {
            EntityColumn column = (EntityColumn) iterator.next();
            sql.append(" AND ").append(column.getColumnEqualsHolder(null));
        }
        sql.append("</where>");
        return sql.toString();
    }

    /**
     * 获取表的UK字段
     *
     * @param entityClass
     * @return
     */
    private static List<EntityColumn> getShardingUKColumns(Class<?> entityClass) {
        if (shardingUKColumnMap.get(entityClass.getName()) != null) {
            return shardingUKColumnMap.get(entityClass.getName());
        }
        //没有则去获取
        List<EntityField> fields = FieldHelper.getAll(entityClass);
        List<EntityColumn> shardingUKColumns = new ArrayList<>();
        for (EntityField field : fields) {
            processField(field, shardingUKColumns);
        }
        shardingUKColumnMap.put(entityClass.getName(), shardingUKColumns);
        return shardingUKColumns;
    }

    /**
     * 解析得到ShardingUk 字段
     *
     * @param field
     */
    private static void processField(EntityField field, List<EntityColumn> shardingUKColumns) {
        // 排除字段
        if (field.isAnnotationPresent(Transient.class)) {
            return;
        }
        // Id
        EntityColumn entityColumn = new EntityColumn();
        // Column
        String columnName = null;
        if (field.isAnnotationPresent(Column.class)) {
            Column column = field.getAnnotation(Column.class);
            columnName = column.name();
        }
        // ColumnType
        if (field.isAnnotationPresent(ColumnType.class)) {
            ColumnType columnType = field.getAnnotation(ColumnType.class);
            // column可以起到别名的作用
            if (StringUtil.isEmpty(columnName) && StringUtil.isNotEmpty(columnType.column())) {
                columnName = columnType.column();
            }
            if (columnType.jdbcType() != JdbcType.UNDEFINED) {
                entityColumn.setJdbcType(columnType.jdbcType());
            }
            if (columnType.typeHandler() != UnknownTypeHandler.class) {
                entityColumn.setTypeHandler(columnType.typeHandler());
            }
        }
        entityColumn.setProperty(field.getName());
        entityColumn.setColumn(columnName);
        entityColumn.setJavaType(field.getJavaType());
        // 扩展增加UK Columns
        if (field.isAnnotationPresent(ShardingUk.class)) {
            shardingUKColumns.add(entityColumn);
        }

    }
}
